import { _decorator, Enum, Sprite, SpriteFrame, UITransform } from 'cc';
import { BUILD, EDITOR } from 'cc/env';
import { MathUtil } from '../../Util/MathUtil';
const { ccclass, property, menu, executionOrder, requireComponent } = _decorator;

enum FixType {
  NORMAL,
  WIDTH,
  HEIGHT,
  All,
}

@ccclass('SpriteRedefine')
@menu('myComponent/SpriteRedefine')
@executionOrder(110)
@requireComponent(UITransform)
export class SpriteRedefine extends Sprite {
  /**
   * @en
   * The sprite frame of the sprite.
   *
   * @zh
   * 精灵的精灵帧。
   */
  @property({
    type: SpriteFrame,
    displayOrder: 5,
    tooltip: '渲染Sprite使用的Sprite Frame图片资源',
    override: true,
  })
  get spriteFrame(): SpriteFrame | null {
    return this._spriteFrame;
  }
  set spriteFrame(value) {
    if (this._spriteFrame === value) {
      return;
    }

    const lastSprite = this._spriteFrame;
    this._spriteFrame = value;
    this.markForUpdateRenderData();
    this._applySpriteFrame(lastSprite);
    if (EDITOR) {
      this.node.emit(Sprite.EventType.SPRITE_FRAME_CHANGED, this);
    }

    this._updateSize();
  }

  private _updateUVs(): void {
    if (this._assembler) {
      this._assembler.updateUVs(this);
    }
  }

  private _applySpriteSize(): void {
    if (this._spriteFrame) {
      if (BUILD || !this._spriteFrame.isDefault) {
        if (Sprite.SizeMode.RAW === this._sizeMode) {
          const size = this._spriteFrame.originalSize;
          this.node._uiProps.uiTransformComp!.setContentSize(size);
        } else if (Sprite.SizeMode.TRIMMED === this._sizeMode) {
          const rect = this._spriteFrame.rect;
          this.node._uiProps.uiTransformComp!.setContentSize(rect.width, rect.height);
        }
      }
    }
  }

  private _applySpriteFrame(oldFrame: SpriteFrame | null): void {
    const spriteFrame = this._spriteFrame;

    if (oldFrame && this._type === Sprite.Type.SLICED) {
      oldFrame.off(SpriteFrame.EVENT_UV_UPDATED, this._updateUVs, this);
    }

    let textureChanged = false;
    if (spriteFrame) {
      if (!oldFrame || oldFrame.texture !== spriteFrame.texture) {
        textureChanged = true;
      }
      if (textureChanged) {
        if (this.renderData) this.renderData.textureDirty = true;
        this.changeMaterialForDefine();
      }
      this._applySpriteSize();
      if (this._type === Sprite.Type.SLICED) {
        spriteFrame.on(SpriteFrame.EVENT_UV_UPDATED, this._updateUVs, this);
      }
    }
  }

  @property({ type: Enum(FixType), tooltip: '适应大小：\nNORMAL:不适应\nWIDTH:适应宽度\nHEIGHT:适应高度\nWIDGET:适应父节点宽高\nAll:适应宽高' })
  get fixType(): FixType {
    return this._fixType;
  }

  set fixType(type: FixType) {
    this._fixType = type;
    this._updateSize();
  }

  @property({ serializable: true })
  private _fixType: FixType = FixType.NORMAL;

  @property({
    visible() {
      return this.fixType == FixType.WIDTH || this.fixType == FixType.All;
    },
  })
  fixWidth: number = 20;

  @property({
    visible() {
      return this.fixType == FixType.HEIGHT || this.fixType == FixType.All;
    },
  })
  fixHeight: number = 20;

  @property({
    tooltip: '自适应是否放大图标',
    visible() {
      return this.fixType != FixType.NORMAL;
    },
  })
  get enlargeIcon(): boolean {
    return this._enlargeIcon;
  }
  set enlargeIcon(boo: boolean) {
    this._enlargeIcon = boo;
    this._updateSize();
  }
  private _enlargeIcon: boolean = false;

  private _updateSize() {
    if (this._spriteFrame && this._fixType != FixType.NORMAL) {
      const size = this._spriteFrame.originalSize;
      if (this.sizeMode == Sprite.SizeMode.CUSTOM) {
        this.onSizeChangeSize(size.width, size.height);
      } else {
        this.onSizeChangeScale(size.width, size.height);
      }
    }
  }

  onSizeChangeScale(ww: number, hh: number) {
    let ss = 1;
    switch (this._fixType) {
      case FixType.WIDTH:
        ss = this.fixWidth / ww;
        break;
      case FixType.HEIGHT:
        ss = this.fixHeight / hh;
        break;
      case FixType.All:
        ss = Math.min(this.fixWidth / ww, this.fixHeight / hh);
        break;
    }
    ss = MathUtil.formatNumber(ss, 2);
    if (ss > 1) {
      if (this._enlargeIcon) {
        this.node.setScale(ss, ss);
      } else {
        this.node.setScale(1, 1);
      }
    } else {
      this.node.setScale(ss, ss);
    }
  }

  onSizeChangeSize(ww: number, hh: number) {
    const form = this.node.getComponent(UITransform);
    switch (this._fixType) {
      case FixType.WIDTH:
        if (this.fixWidth < ww || this._enlargeIcon) {
          const ss = this.fixWidth / ww;
          form.width = this.fixWidth;
          form.height = hh * ss;
        } else {
          form.width = ww;
          form.height = hh;
        }
        break;
      case FixType.HEIGHT:
        if (this.fixHeight < hh || this._enlargeIcon) {
          const ss = this.fixHeight / hh;
          form.height = this.fixHeight;
          form.width = ww * ss;
        } else {
          form.width = ww;
          form.height = hh;
        }
        break;
      case FixType.All:
        if (this.fixWidth > ww && this.fixHeight > hh && !this._enlargeIcon) {
          form.width = ww;
          form.height = hh;
        } else {
          const ss1 = this.fixWidth / ww;
          const ss2 = this.fixHeight / hh;
          if (ss1 < ss2) {
            form.width = this.fixWidth;
            form.height = hh * ss1;
          } else {
            form.width = ww * ss2;
            form.height = this.fixHeight;
          }
        }
        break;
    }
  }
}
